package com.apes.framework.plugin.fsm.snapshot;

import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.cache.Cache;
import com.apes.framework.plugin.fsm.FsmFlowInstance;
import com.apes.framework.plugin.fsm.FsmFlowInstanceRepository;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.DateUtil;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service
public class FsmSnapshotService extends DomainService {

    private FsmSnapshotRepository repository;
    private final FsmFlowInstanceRepository fiRepository;
    private final Cache cache;

    public FsmSnapshotService(FsmSnapshotRepository repository, FsmFlowInstanceRepository fiRepository, Cache cache) {
        this.repository = repository;
        this.fiRepository = fiRepository;
        this.cache = cache;
    }

    public FsmSnapshot save(String id, String snapshot) {
        FsmSnapshot fsmSnapshot = new FsmSnapshot();
        fsmSnapshot.setId(id);
        fsmSnapshot.setSnapshot(snapshot);
        return repository.save(fsmSnapshot);
    }

    public String getSnapshot(String id) {
        FsmSnapshot fsmSnapshot = repository.findById(id).orElse(null);
        if (fsmSnapshot == null) return null;
        return fsmSnapshot.getSnapshot();
    }

    @OutboxSubscriber(name = "删除状态机快照", condition = "finished == true")
    public void deleteSnapshot(FsmFlowInstance fi) {
        String id = fi.getId();
        if (fi.isFinished()) {
            repository.deleteById(id);
        }
    }

    public void init() {
        String cacheId = "fsm.snapshot.init";
        int size = 2000;
        Date createDate = DateUtil.add(new Date(), Calendar.MONTH, -6);
        Specification<FsmFlowInstance> specification;
        while (true) {
            Object id = cache.get(cacheId);
            if (id == null) {
                specification = JpaDsl.toCriteria("finished", JpaDsl.eq, false, "createDate", JpaDsl.gte, createDate);
            } else {
                specification = JpaDsl.toCriteria("finished", JpaDsl.eq, false, "createDate", JpaDsl.gte, createDate, "id", JpaDsl.gt, id);
            }
            List<FsmFlowInstance> flowInstances = fiRepository.findAll(specification, PageRequest.of(0, size, new Sort(Sort.Direction.ASC, "id"))).getContent();
            flowInstances.stream().forEach(fi -> {
                FsmSnapshot fsmSnapshot = repository.findById(fi.getId()).orElse(null);
                if (fsmSnapshot == null && StringUtils.hasText(fi.getSnapshot())) {
                    save(fi.getId(), fi.getSnapshot());
                }
                cache.put(cacheId, fi.getId());
            });
            if (flowInstances.size() < size) {
                break;
            }
        }
    }

}
